#include <iostream>
#include "include/value.h"
#include "include/writer.h"
#include <utility>
#include <stdexcept>
#include <cstring>
#include <cassert>

#ifdef JSON_USE_CPPTL
# include <cpptl/conststring.h>
#endif

#include <cstddef>    // size_t

#ifndef JSON_USE_SIMPLE_INTERNAL_ALLOCATOR

# include "include/json_batchallocator.h"

#endif // #ifndef JSON_USE_SIMPLE_INTERNAL_ALLOCATOR

#define JSON_ASSERT_UNREACHABLE assert( false )
#define JSON_ASSERT(condition) assert( condition );  // @todo <= change this into an exception throw
#define JSON_ASSERT_MESSAGE(condition, message) if (!( condition )) throw std::runtime_error( message );

namespace Json {

    const Value Value::null;
    const Int Value::minInt = Int(~(UInt(-1) / 2));
    const Int Value::maxInt = Int(UInt(-1) / 2);
    const UInt Value::maxUInt = UInt(-1);

// A "safe" implementation of strdup. Allow null pointer to be passed. 
// Also avoid warning on msvc80.
//
//inline char *safeStringDup( const char *czstring )
//{
//   if ( czstring )
//   {
//      const size_t length = (unsigned int)( strlen(czstring) + 1 );
//      char *newString = static_cast<char *>( malloc( length ) );
//      memcpy( newString, czstring, length );
//      return newString;
//   }
//   return 0;
//}
//
//inline char *safeStringDup( const std::string &str )
//{
//   if ( !str.empty() )
//   {
//      const size_t length = str.length();
//      char *newString = static_cast<char *>( malloc( length + 1 ) );
//      memcpy( newString, str.c_str(), length );
//      newString[length] = 0;
//      return newString;
//   }
//   return 0;
//}

    ValueAllocator::~ValueAllocator() {
    }

    class DefaultValueAllocator : public ValueAllocator {
    public:
        virtual ~DefaultValueAllocator() {
        }

        virtual char *makeMemberName(const char *memberName) {
            return duplicateStringValue(memberName);
        }

        virtual void releaseMemberName(char *memberName) {
            releaseStringValue(memberName);
        }

        virtual char *duplicateStringValue(const char *value,
                                           unsigned int length = unknown) {
            //@todo invesgate this old optimization
            //if ( !value  ||  value[0] == 0 )
            //   return 0;

            if (length == unknown)
                length = (unsigned int) strlen(value);
            char *newString = static_cast<char *>( malloc(length + 1));
            memcpy(newString, value, length);
            newString[length] = 0;
            return newString;
        }

        virtual void releaseStringValue(char *value) {
            if (value)
                free(value);
        }
    };

    static ValueAllocator *&valueAllocator() {
        static DefaultValueAllocator defaultAllocator;
        static ValueAllocator *valueAllocator = &defaultAllocator;
        return valueAllocator;
    }

    static struct DummyValueAllocatorInitializer {
        DummyValueAllocatorInitializer() {
            valueAllocator();      // ensure valueAllocator() statics are initialized before main().
        }
    } dummyValueAllocatorInitializer;



// //////////////////////////////////////////////////////////////////
// //////////////////////////////////////////////////////////////////
// //////////////////////////////////////////////////////////////////
// ValueInternals...
// //////////////////////////////////////////////////////////////////
// //////////////////////////////////////////////////////////////////
// //////////////////////////////////////////////////////////////////
#ifdef JSON_VALUE_USE_INTERNAL_MAP
# include "json_internalarray.inl"
# include "json_internalmap.inl"
#endif // JSON_VALUE_USE_INTERNAL_MAP

# include "json_valueiterator.inl"


// //////////////////////////////////////////////////////////////////
// //////////////////////////////////////////////////////////////////
// //////////////////////////////////////////////////////////////////
// class Value::CommentInfo
// //////////////////////////////////////////////////////////////////
// //////////////////////////////////////////////////////////////////
// //////////////////////////////////////////////////////////////////


    Value::CommentInfo::CommentInfo()
            : comment_(0) {
    }

    Value::CommentInfo::~CommentInfo() {
        if (comment_)
            valueAllocator()->releaseStringValue(comment_);
    }


    void
    Value::CommentInfo::setComment(const char *text) {
        if (comment_)
            valueAllocator()->releaseStringValue(comment_);
        JSON_ASSERT(text);
        JSON_ASSERT_MESSAGE(text[0] == '\0' || text[0] == '/', "Comments must start with /");
        // It seems that /**/ style comments are acceptable as well.
        comment_ = valueAllocator()->duplicateStringValue(text);
    }


// //////////////////////////////////////////////////////////////////
// //////////////////////////////////////////////////////////////////
// //////////////////////////////////////////////////////////////////
// class Value::CZString
// //////////////////////////////////////////////////////////////////
// //////////////////////////////////////////////////////////////////
// //////////////////////////////////////////////////////////////////
# ifndef JSON_VALUE_USE_INTERNAL_MAP

// Notes: index_ indicates if the string was allocated when
// a string is stored.

    Value::CZString::CZString(int index)
            : cstr_(0), index_(index) {
    }

    Value::CZString::CZString(const char *cstr, DuplicationPolicy allocate)
            : cstr_(allocate == duplicate ? valueAllocator()->makeMemberName(cstr)
                                          : cstr), index_(allocate) {
    }

    Value::CZString::CZString(const CZString &other)
            : cstr_(other.index_ != noDuplication && other.cstr_ != 0
                    ? valueAllocator()->makeMemberName(other.cstr_)
                    : other.cstr_),
              index_(other.cstr_ ? (other.index_ == noDuplication ? noDuplication : duplicate)
                                 : other.index_) {
    }

    Value::CZString::~CZString() {
        if (cstr_ && index_ == duplicate)
            valueAllocator()->releaseMemberName(const_cast<char *>( cstr_ ));
    }

    void
    Value::CZString::swap(CZString &other) {
        std::swap(cstr_, other.cstr_);
        std::swap(index_, other.index_);
    }

    Value::CZString &
    Value::CZString::operator=(const CZString &other) {
        CZString temp(other);
        swap(temp);
        return *this;
    }

    bool
    Value::CZString::operator<(const CZString &other) const {
        if (cstr_)
            return strcmp(cstr_, other.cstr_) < 0;
        return index_ < other.index_;
    }

    bool
    Value::CZString::operator==(const CZString &other) const {
        if (cstr_)
            return strcmp(cstr_, other.cstr_) == 0;
        return index_ == other.index_;
    }


    int
    Value::CZString::index() const {
        return index_;
    }


    const char *
    Value::CZString::c_str() const {
        return cstr_;
    }

    bool
    Value::CZString::isStaticString() const {
        return index_ == noDuplication;
    }

#endif // ifndef JSON_VALUE_USE_INTERNAL_MAP


// //////////////////////////////////////////////////////////////////
// //////////////////////////////////////////////////////////////////
// //////////////////////////////////////////////////////////////////
// class Value::Value
// //////////////////////////////////////////////////////////////////
// //////////////////////////////////////////////////////////////////
// //////////////////////////////////////////////////////////////////

/*! \internal Default constructor initialization must be equivalent to:
 * memset( this, 0, sizeof(Value) )
 * This optimization is used in ValueInternalMap fast allocator.
 */
    Value::Value(ValueType type)
            : type_(type), allocated_(0), comments_(0)
# ifdef JSON_VALUE_USE_INTERNAL_MAP
    , itemIsUsed_( 0 )
#endif
    {
        switch (type) {
            case nullValue:
                break;
            case intValue:
            case uintValue:
                value_.int_ = 0;
                break;
            case realValue:
                value_.real_ = 0.0;
                break;
            case stringValue:
                value_.string_ = 0;
                break;
#ifndef JSON_VALUE_USE_INTERNAL_MAP
            case arrayValue:
            case objectValue:
                value_.map_ = new ObjectValues();
                break;
#else
            case arrayValue:
               value_.array_ = arrayAllocator()->newArray();
               break;
            case objectValue:
               value_.map_ = mapAllocator()->newMap();
               break;
#endif
            case booleanValue:
                value_.bool_ = false;
                break;
            default:
                JSON_ASSERT_UNREACHABLE;
        }
    }


    Value::Value(Int value)
            : type_(intValue), comments_(0)
# ifdef JSON_VALUE_USE_INTERNAL_MAP
    , itemIsUsed_( 0 )
#endif
    {
        value_.int_ = value;
    }


    Value::Value(UInt value)
            : type_(uintValue), comments_(0)
# ifdef JSON_VALUE_USE_INTERNAL_MAP
    , itemIsUsed_( 0 )
#endif
    {
        value_.uint_ = value;
    }

    Value::Value(double value)
            : type_(realValue), comments_(0)
# ifdef JSON_VALUE_USE_INTERNAL_MAP
    , itemIsUsed_( 0 )
#endif
    {
        value_.real_ = value;
    }

    Value::Value(const char *value)
            : type_(stringValue), allocated_(true), comments_(0)
# ifdef JSON_VALUE_USE_INTERNAL_MAP
    , itemIsUsed_( 0 )
#endif
    {
        value_.string_ = valueAllocator()->duplicateStringValue(value);
    }


    Value::Value(const char *beginValue,
                 const char *endValue)
            : type_(stringValue), allocated_(true), comments_(0)
# ifdef JSON_VALUE_USE_INTERNAL_MAP
    , itemIsUsed_( 0 )
#endif
    {
        value_.string_ = valueAllocator()->duplicateStringValue(beginValue,
                                                                UInt(endValue - beginValue));
    }


    Value::Value(const std::string &value)
            : type_(stringValue), allocated_(true), comments_(0)
# ifdef JSON_VALUE_USE_INTERNAL_MAP
    , itemIsUsed_( 0 )
#endif
    {
        value_.string_ = valueAllocator()->duplicateStringValue(value.c_str(),
                                                                (unsigned int) value.length());

    }

    Value::Value(const StaticString &value)
            : type_(stringValue), allocated_(false), comments_(0)
# ifdef JSON_VALUE_USE_INTERNAL_MAP
    , itemIsUsed_( 0 )
#endif
    {
        value_.string_ = const_cast<char *>( value.c_str());
    }


# ifdef JSON_USE_CPPTL
    Value::Value( const CppTL::ConstString &value )
       : type_( stringValue )
       , allocated_( true )
       , comments_( 0 )
# ifdef JSON_VALUE_USE_INTERNAL_MAP
       , itemIsUsed_( 0 )
#endif
    {
       value_.string_ = valueAllocator()->duplicateStringValue( value, value.length() );
    }
# endif

    Value::Value(bool value)
            : type_(booleanValue), comments_(0)
# ifdef JSON_VALUE_USE_INTERNAL_MAP
    , itemIsUsed_( 0 )
#endif
    {
        value_.bool_ = value;
    }


    Value::Value(const Value &other)
            : type_(other.type_), comments_(0)
# ifdef JSON_VALUE_USE_INTERNAL_MAP
    , itemIsUsed_( 0 )
#endif
    {
        switch (type_) {
            case nullValue:
            case intValue:
            case uintValue:
            case realValue:
            case booleanValue:
                value_ = other.value_;
                break;
            case stringValue:
                if (other.value_.string_) {
                    value_.string_ = valueAllocator()->duplicateStringValue(other.value_.string_);
                    allocated_ = true;
                } else
                    value_.string_ = 0;
                break;
#ifndef JSON_VALUE_USE_INTERNAL_MAP
            case arrayValue:
            case objectValue:
                value_.map_ = new ObjectValues(*other.value_.map_);
                break;
#else
            case arrayValue:
               value_.array_ = arrayAllocator()->newArrayCopy( *other.value_.array_ );
               break;
            case objectValue:
               value_.map_ = mapAllocator()->newMapCopy( *other.value_.map_ );
               break;
#endif
            default:
                JSON_ASSERT_UNREACHABLE;
        }
        if (other.comments_) {
            comments_ = new CommentInfo[numberOfCommentPlacement];
            for (int comment = 0; comment < numberOfCommentPlacement; ++comment) {
                const CommentInfo &otherComment = other.comments_[comment];
                if (otherComment.comment_)
                    comments_[comment].setComment(otherComment.comment_);
            }
        }
    }


    Value::~Value() {
        switch (type_) {
            case nullValue:
            case intValue:
            case uintValue:
            case realValue:
            case booleanValue:
                break;
            case stringValue:
                if (allocated_)
                    valueAllocator()->releaseStringValue(value_.string_);
                break;
#ifndef JSON_VALUE_USE_INTERNAL_MAP
            case arrayValue:
            case objectValue:
                delete value_.map_;
                break;
#else
            case arrayValue:
               arrayAllocator()->destructArray( value_.array_ );
               break;
            case objectValue:
               mapAllocator()->destructMap( value_.map_ );
               break;
#endif
            default:
                JSON_ASSERT_UNREACHABLE;
        }

        if (comments_)
            delete[] comments_;
    }

    Value &
    Value::operator=(const Value &other) {
        Value temp(other);
        swap(temp);
        return *this;
    }

    void
    Value::swap(Value &other) {
        ValueType temp = type_;
        type_ = other.type_;
        other.type_ = temp;
        std::swap(value_, other.value_);
        int temp2 = allocated_;
        allocated_ = other.allocated_;
        other.allocated_ = temp2;
    }

    ValueType
    Value::type() const {
        return type_;
    }


    int
    Value::compare(const Value &other) {
        /*
        int typeDelta = other.type_ - type_;
        switch ( type_ )
        {
        case nullValue:

           return other.type_ == type_;
        case intValue:
           if ( other.type_.isNumeric()
        case uintValue:
        case realValue:
        case booleanValue:
           break;
        case stringValue,
           break;
        case arrayValue:
           delete value_.array_;
           break;
        case objectValue:
           delete value_.map_;
        default:
           JSON_ASSERT_UNREACHABLE;
        }
        */
        return 0;  // unreachable
    }

    bool
    Value::operator<(const Value &other) const {
        int typeDelta = type_ - other.type_;
        if (typeDelta)
            return typeDelta < 0 ? true : false;
        switch (type_) {
            case nullValue:
                return false;
            case intValue:
                return value_.int_ < other.value_.int_;
            case uintValue:
                return value_.uint_ < other.value_.uint_;
            case realValue:
                return value_.real_ < other.value_.real_;
            case booleanValue:
                return value_.bool_ < other.value_.bool_;
            case stringValue:
                return (value_.string_ == 0 && other.value_.string_)
                       || (other.value_.string_
                           && value_.string_
                           && strcmp(value_.string_, other.value_.string_) < 0);
#ifndef JSON_VALUE_USE_INTERNAL_MAP
            case arrayValue:
            case objectValue: {
                int delta = int(value_.map_->size() - other.value_.map_->size());
                if (delta)
                    return delta < 0;
                return (*value_.map_) < (*other.value_.map_);
            }
#else
            case arrayValue:
               return value_.array_->compare( *(other.value_.array_) ) < 0;
            case objectValue:
               return value_.map_->compare( *(other.value_.map_) ) < 0;
#endif
            default:
                JSON_ASSERT_UNREACHABLE;
        }
        return 0;  // unreachable
    }

    bool
    Value::operator<=(const Value &other) const {
        return !(other > *this);
    }

    bool
    Value::operator>=(const Value &other) const {
        return !(*this < other);
    }

    bool
    Value::operator>(const Value &other) const {
        return other < *this;
    }

    bool
    Value::operator==(const Value &other) const {
        //if ( type_ != other.type_ )
        // GCC 2.95.3 says:
        // attempt to take address of bit-field structure member `Json::Value::type_'
        // Beats me, but a temp solves the problem.
        int temp = other.type_;
        if (type_ != temp)
            return false;
        switch (type_) {
            case nullValue:
                return true;
            case intValue:
                return value_.int_ == other.value_.int_;
            case uintValue:
                return value_.uint_ == other.value_.uint_;
            case realValue:
                return value_.real_ == other.value_.real_;
            case booleanValue:
                return value_.bool_ == other.value_.bool_;
            case stringValue:
                return (value_.string_ == other.value_.string_)
                       || (other.value_.string_
                           && value_.string_
                           && strcmp(value_.string_, other.value_.string_) == 0);
#ifndef JSON_VALUE_USE_INTERNAL_MAP
            case arrayValue:
            case objectValue:
                return value_.map_->size() == other.value_.map_->size()
                       && (*value_.map_) == (*other.value_.map_);
#else
            case arrayValue:
               return value_.array_->compare( *(other.value_.array_) ) == 0;
            case objectValue:
               return value_.map_->compare( *(other.value_.map_) ) == 0;
#endif
            default:
                JSON_ASSERT_UNREACHABLE;
        }
        return 0;  // unreachable
    }

    bool
    Value::operator!=(const Value &other) const {
        return !(*this == other);
    }

    const char *
    Value::asCString() const {
        JSON_ASSERT(type_ == stringValue);
        return value_.string_;
    }


    std::string
    Value::asString() const {
        switch (type_) {
            case nullValue:
                return "";
            case stringValue:
                return value_.string_ ? value_.string_ : "";
            case booleanValue:
                return value_.bool_ ? "true" : "false";
            case intValue:
            case uintValue:
            case realValue:
            case arrayValue:
            case objectValue:
                JSON_ASSERT_MESSAGE(false, "Type is not convertible to string");
            default:
                JSON_ASSERT_UNREACHABLE;
        }
        return ""; // unreachable
    }

# ifdef JSON_USE_CPPTL
    CppTL::ConstString
    Value::asConstString() const
    {
       return CppTL::ConstString( asString().c_str() );
    }
# endif

    Value::Int
    Value::asInt() const {
        switch (type_) {
            case nullValue:
                return 0;
            case intValue:
                return value_.int_;
            case uintValue:
                JSON_ASSERT_MESSAGE(value_.uint_ < (unsigned) maxInt,
                                    "integer out of signed integer range");
                return value_.uint_;
            case realValue:
                JSON_ASSERT_MESSAGE(value_.real_ >= minInt && value_.real_ <= maxInt,
                                    "Real out of signed integer range");
                return Int(value_.real_);
            case booleanValue:
                return value_.bool_ ? 1 : 0;
            case stringValue:
            case arrayValue:
            case objectValue:
                JSON_ASSERT_MESSAGE(false, "Type is not convertible to int");
            default:
                JSON_ASSERT_UNREACHABLE;
        }
        return 0; // unreachable;
    }

    Value::UInt
    Value::asUInt() const {
        switch (type_) {
            case nullValue:
                return 0;
            case intValue:
                JSON_ASSERT_MESSAGE(value_.int_ >= 0,
                                    "Negative integer can not be converted to unsigned integer");
                return value_.int_;
            case uintValue:
                return value_.uint_;
            case realValue:
                JSON_ASSERT_MESSAGE(value_.real_ >= 0 && value_.real_ <= maxUInt,
                                    "Real out of unsigned integer range");
                return UInt(value_.real_);
            case booleanValue:
                return value_.bool_ ? 1 : 0;
            case stringValue:
            case arrayValue:
            case objectValue:
                JSON_ASSERT_MESSAGE(false, "Type is not convertible to uint");
            default:
                JSON_ASSERT_UNREACHABLE;
        }
        return 0; // unreachable;
    }

    double
    Value::asDouble() const {
        switch (type_) {
            case nullValue:
                return 0.0;
            case intValue:
                return value_.int_;
            case uintValue:
                return value_.uint_;
            case realValue:
                return value_.real_;
            case booleanValue:
                return value_.bool_ ? 1.0 : 0.0;
            case stringValue:
            case arrayValue:
            case objectValue:
                JSON_ASSERT_MESSAGE(false, "Type is not convertible to double");
            default:
                JSON_ASSERT_UNREACHABLE;
        }
        return 0; // unreachable;
    }

    bool
    Value::asBool() const {
        switch (type_) {
            case nullValue:
                return false;
            case intValue:
            case uintValue:
                return value_.int_ != 0;
            case realValue:
                return value_.real_ != 0.0;
            case booleanValue:
                return value_.bool_;
            case stringValue:
                return value_.string_ && value_.string_[0] != 0;
            case arrayValue:
            case objectValue:
                return value_.map_->size() != 0;
            default:
                JSON_ASSERT_UNREACHABLE;
        }
        return false; // unreachable;
    }


    bool
    Value::isConvertibleTo(ValueType other) const {
        switch (type_) {
            case nullValue:
                return true;
            case intValue:
                return (other == nullValue && value_.int_ == 0)
                       || other == intValue
                       || (other == uintValue && value_.int_ >= 0)
                       || other == realValue
                       || other == stringValue
                       || other == booleanValue;
            case uintValue:
                return (other == nullValue && value_.uint_ == 0)
                       || (other == intValue && value_.uint_ <= (unsigned) maxInt)
                       || other == uintValue
                       || other == realValue
                       || other == stringValue
                       || other == booleanValue;
            case realValue:
                return (other == nullValue && value_.real_ == 0.0)
                       || (other == intValue && value_.real_ >= minInt && value_.real_ <= maxInt)
                       || (other == uintValue && value_.real_ >= 0 && value_.real_ <= maxUInt)
                       || other == realValue
                       || other == stringValue
                       || other == booleanValue;
            case booleanValue:
                return (other == nullValue && value_.bool_ == false)
                       || other == intValue
                       || other == uintValue
                       || other == realValue
                       || other == stringValue
                       || other == booleanValue;
            case stringValue:
                return other == stringValue
                       || (other == nullValue && (!value_.string_ || value_.string_[0] == 0));
            case arrayValue:
                return other == arrayValue
                       || (other == nullValue && value_.map_->size() == 0);
            case objectValue:
                return other == objectValue
                       || (other == nullValue && value_.map_->size() == 0);
            default:
                JSON_ASSERT_UNREACHABLE;
        }
        return false; // unreachable;
    }


/// Number of values in array or object
    Value::UInt
    Value::size() const {
        switch (type_) {
            case nullValue:
            case intValue:
            case uintValue:
            case realValue:
            case booleanValue:
            case stringValue:
                return 0;
#ifndef JSON_VALUE_USE_INTERNAL_MAP
            case arrayValue:  // size of the array is highest index + 1
                if (!value_.map_->empty()) {
                    ObjectValues::const_iterator itLast = value_.map_->end();
                    --itLast;
                    return (*itLast).first.index() + 1;
                }
                return 0;
            case objectValue:
                return Int(value_.map_->size());
#else
            case arrayValue:
               return Int( value_.array_->size() );
            case objectValue:
               return Int( value_.map_->size() );
#endif
            default:
                JSON_ASSERT_UNREACHABLE;
        }
        return 0; // unreachable;
    }


    bool
    Value::empty() const {
        if (isNull() || isArray() || isObject())
            return size() == 0u;
        else
            return false;
    }


    bool
    Value::operator!() const {
        return isNull();
    }


    void
    Value::clear() {
        JSON_ASSERT(type_ == nullValue || type_ == arrayValue || type_ == objectValue);

        switch (type_) {
#ifndef JSON_VALUE_USE_INTERNAL_MAP
            case arrayValue:
            case objectValue:
                value_.map_->clear();
                break;
#else
            case arrayValue:
               value_.array_->clear();
               break;
            case objectValue:
               value_.map_->clear();
               break;
#endif
            default:
                break;
        }
    }

    void
    Value::resize(UInt newSize) {
        JSON_ASSERT(type_ == nullValue || type_ == arrayValue);
        if (type_ == nullValue)
            *this = Value(arrayValue);
#ifndef JSON_VALUE_USE_INTERNAL_MAP
        UInt oldSize = size();
        if (newSize == 0)
            clear();
        else if (newSize > oldSize)
            (*this)[newSize - 1];
        else {
            for (UInt index = newSize; index < oldSize; ++index)
                value_.map_->erase(index);
            assert(size() == newSize);
        }
#else
        value_.array_->resize( newSize );
#endif
    }


    Value &
    Value::operator[](UInt index) {
        JSON_ASSERT(type_ == nullValue || type_ == arrayValue);
        if (type_ == nullValue)
            *this = Value(arrayValue);
#ifndef JSON_VALUE_USE_INTERNAL_MAP
        CZString key(index);
        ObjectValues::iterator it = value_.map_->lower_bound(key);
        if (it != value_.map_->end() && (*it).first == key)
            return (*it).second;

        ObjectValues::value_type defaultValue(key, null);
        it = value_.map_->insert(it, defaultValue);
        return (*it).second;
#else
        return value_.array_->resolveReference( index );
#endif
    }


    const Value &
    Value::operator[](UInt index) const {
        JSON_ASSERT(type_ == nullValue || type_ == arrayValue);
        if (type_ == nullValue)
            return null;
#ifndef JSON_VALUE_USE_INTERNAL_MAP
        CZString key(index);
        ObjectValues::const_iterator it = value_.map_->find(key);
        if (it == value_.map_->end())
            return null;
        return (*it).second;
#else
        Value *value = value_.array_->find( index );
        return value ? *value : null;
#endif
    }


    Value &
    Value::operator[](const char *key) {
        return resolveReference(key, false);
    }


    Value &
    Value::resolveReference(const char *key,
                            bool isStatic) {
        JSON_ASSERT(type_ == nullValue || type_ == objectValue);
        if (type_ == nullValue)
            *this = Value(objectValue);
#ifndef JSON_VALUE_USE_INTERNAL_MAP
        CZString actualKey(key, isStatic ? CZString::noDuplication
                                         : CZString::duplicateOnCopy);
        ObjectValues::iterator it = value_.map_->lower_bound(actualKey);
        if (it != value_.map_->end() && (*it).first == actualKey)
            return (*it).second;

        ObjectValues::value_type defaultValue(actualKey, null);
        it = value_.map_->insert(it, defaultValue);
        Value &value = (*it).second;
        return value;
#else
        return value_.map_->resolveReference( key, isStatic );
#endif
    }


    Value
    Value::get(UInt index,
               const Value &defaultValue) const {
        const Value *value = &((*this)[index]);
        return value == &null ? defaultValue : *value;
    }


    bool
    Value::isValidIndex(UInt index) const {
        return index < size();
    }


    const Value &
    Value::operator[](const char *key) const {
        JSON_ASSERT(type_ == nullValue || type_ == objectValue);
        if (type_ == nullValue)
            return null;
#ifndef JSON_VALUE_USE_INTERNAL_MAP
        CZString actualKey(key, CZString::noDuplication);
        ObjectValues::const_iterator it = value_.map_->find(actualKey);
        if (it == value_.map_->end())
            return null;
        return (*it).second;
#else
        const Value *value = value_.map_->find( key );
        return value ? *value : null;
#endif
    }


    Value &
    Value::operator[](const std::string &key) {
        return (*this)[key.c_str()];
    }


    const Value &
    Value::operator[](const std::string &key) const {
        return (*this)[key.c_str()];
    }

    Value &
    Value::operator[](const StaticString &key) {
        return resolveReference(key, true);
    }


# ifdef JSON_USE_CPPTL
    Value &
    Value::operator[]( const CppTL::ConstString &key )
    {
       return (*this)[ key.c_str() ];
    }


    const Value &
    Value::operator[]( const CppTL::ConstString &key ) const
    {
       return (*this)[ key.c_str() ];
    }
# endif


    Value &
    Value::append(const Value &value) {
        return (*this)[size()] = value;
    }


    Value
    Value::get(const char *key,
               const Value &defaultValue) const {
        const Value *value = &((*this)[key]);
        return value == &null ? defaultValue : *value;
    }


    Value
    Value::get(const std::string &key,
               const Value &defaultValue) const {
        return get(key.c_str(), defaultValue);
    }

    Value
    Value::removeMember(const char *key) {
        JSON_ASSERT(type_ == nullValue || type_ == objectValue);
        if (type_ == nullValue)
            return null;
#ifndef JSON_VALUE_USE_INTERNAL_MAP
        CZString actualKey(key, CZString::noDuplication);
        ObjectValues::iterator it = value_.map_->find(actualKey);
        if (it == value_.map_->end())
            return null;
        Value old(it->second);
        value_.map_->erase(it);
        return old;
#else
        Value *value = value_.map_->find( key );
        if (value){
           Value old(*value);
           value_.map_.remove( key );
           return old;
        } else {
           return null;
        }
#endif
    }

    Value
    Value::removeMember(const std::string &key) {
        return removeMember(key.c_str());
    }

# ifdef JSON_USE_CPPTL
    Value
    Value::get( const CppTL::ConstString &key,
                const Value &defaultValue ) const
    {
       return get( key.c_str(), defaultValue );
    }
# endif

    bool
    Value::isMember(const char *key) const {
        const Value *value = &((*this)[key]);
        return value != &null;
    }


    bool
    Value::isMember(const std::string &key) const {
        return isMember(key.c_str());
    }


# ifdef JSON_USE_CPPTL
    bool
    Value::isMember( const CppTL::ConstString &key ) const
    {
       return isMember( key.c_str() );
    }
#endif

    Value::Members
    Value::getMemberNames() const {
        JSON_ASSERT(type_ == nullValue || type_ == objectValue);
        if (type_ == nullValue)
            return Value::Members();
        Members members;
        members.reserve(value_.map_->size());
#ifndef JSON_VALUE_USE_INTERNAL_MAP
        ObjectValues::const_iterator it = value_.map_->begin();
        ObjectValues::const_iterator itEnd = value_.map_->end();
        for (; it != itEnd; ++it)
            members.push_back(std::string((*it).first.c_str()));
#else
        ValueInternalMap::IteratorState it;
        ValueInternalMap::IteratorState itEnd;
        value_.map_->makeBeginIterator( it );
        value_.map_->makeEndIterator( itEnd );
        for ( ; !ValueInternalMap::equals( it, itEnd ); ValueInternalMap::increment(it) )
           members.push_back( std::string( ValueInternalMap::key( it ) ) );
#endif
        return members;
    }
//
//# ifdef JSON_USE_CPPTL
//EnumMemberNames
//Value::enumMemberNames() const
//{
//   if ( type_ == objectValue )
//   {
//      return CppTL::Enum::any(  CppTL::Enum::transform(
//         CppTL::Enum::keys( *(value_.map_), CppTL::Type<const CZString &>() ),
//         MemberNamesTransform() ) );
//   }
//   return EnumMemberNames();
//}
//
//
//EnumValues 
//Value::enumValues() const
//{
//   if ( type_ == objectValue  ||  type_ == arrayValue )
//      return CppTL::Enum::anyValues( *(value_.map_), 
//                                     CppTL::Type<const Value &>() );
//   return EnumValues();
//}
//
//# endif


    bool
    Value::isNull() const {
        return type_ == nullValue;
    }


    bool
    Value::isBool() const {
        return type_ == booleanValue;
    }


    bool
    Value::isInt() const {
        return type_ == intValue;
    }


    bool
    Value::isUInt() const {
        return type_ == uintValue;
    }


    bool
    Value::isIntegral() const {
        return type_ == intValue
               || type_ == uintValue
               || type_ == booleanValue;
    }


    bool
    Value::isDouble() const {
        return type_ == realValue;
    }


    bool
    Value::isNumeric() const {
        return isIntegral() || isDouble();
    }


    bool
    Value::isString() const {
        return type_ == stringValue;
    }


    bool
    Value::isArray() const {
        return type_ == nullValue || type_ == arrayValue;
    }


    bool
    Value::isObject() const {
        return type_ == nullValue || type_ == objectValue;
    }


    void
    Value::setComment(const char *comment,
                      CommentPlacement placement) {
        if (!comments_)
            comments_ = new CommentInfo[numberOfCommentPlacement];
        comments_[placement].setComment(comment);
    }


    void
    Value::setComment(const std::string &comment,
                      CommentPlacement placement) {
        setComment(comment.c_str(), placement);
    }


    bool
    Value::hasComment(CommentPlacement placement) const {
        return comments_ != 0 && comments_[placement].comment_ != 0;
    }

    std::string
    Value::getComment(CommentPlacement placement) const {
        if (hasComment(placement))
            return comments_[placement].comment_;
        return "";
    }


    std::string
    Value::toStyledString() const {
        StyledWriter writer;
        return writer.write(*this);
    }


    Value::const_iterator
    Value::begin() const {
        switch (type_) {
#ifdef JSON_VALUE_USE_INTERNAL_MAP
            case arrayValue:
               if ( value_.array_ )
               {
                  ValueInternalArray::IteratorState it;
                  value_.array_->makeBeginIterator( it );
                  return const_iterator( it );
               }
               break;
            case objectValue:
               if ( value_.map_ )
               {
                  ValueInternalMap::IteratorState it;
                  value_.map_->makeBeginIterator( it );
                  return const_iterator( it );
               }
               break;
#else
            case arrayValue:
            case objectValue:
                if (value_.map_)
                    return const_iterator(value_.map_->begin());
                break;
#endif
            default:
                break;
        }
        return const_iterator();
    }

    Value::const_iterator
    Value::end() const {
        switch (type_) {
#ifdef JSON_VALUE_USE_INTERNAL_MAP
            case arrayValue:
               if ( value_.array_ )
               {
                  ValueInternalArray::IteratorState it;
                  value_.array_->makeEndIterator( it );
                  return const_iterator( it );
               }
               break;
            case objectValue:
               if ( value_.map_ )
               {
                  ValueInternalMap::IteratorState it;
                  value_.map_->makeEndIterator( it );
                  return const_iterator( it );
               }
               break;
#else
            case arrayValue:
            case objectValue:
                if (value_.map_)
                    return const_iterator(value_.map_->end());
                break;
#endif
            default:
                break;
        }
        return const_iterator();
    }


    Value::iterator
    Value::begin() {
        switch (type_) {
#ifdef JSON_VALUE_USE_INTERNAL_MAP
            case arrayValue:
               if ( value_.array_ )
               {
                  ValueInternalArray::IteratorState it;
                  value_.array_->makeBeginIterator( it );
                  return iterator( it );
               }
               break;
            case objectValue:
               if ( value_.map_ )
               {
                  ValueInternalMap::IteratorState it;
                  value_.map_->makeBeginIterator( it );
                  return iterator( it );
               }
               break;
#else
            case arrayValue:
            case objectValue:
                if (value_.map_)
                    return iterator(value_.map_->begin());
                break;
#endif
            default:
                break;
        }
        return iterator();
    }

    Value::iterator
    Value::end() {
        switch (type_) {
#ifdef JSON_VALUE_USE_INTERNAL_MAP
            case arrayValue:
               if ( value_.array_ )
               {
                  ValueInternalArray::IteratorState it;
                  value_.array_->makeEndIterator( it );
                  return iterator( it );
               }
               break;
            case objectValue:
               if ( value_.map_ )
               {
                  ValueInternalMap::IteratorState it;
                  value_.map_->makeEndIterator( it );
                  return iterator( it );
               }
               break;
#else
            case arrayValue:
            case objectValue:
                if (value_.map_)
                    return iterator(value_.map_->end());
                break;
#endif
            default:
                break;
        }
        return iterator();
    }


// class PathArgument
// //////////////////////////////////////////////////////////////////

    PathArgument::PathArgument()
            : kind_(kindNone) {
    }


    PathArgument::PathArgument(Value::UInt index)
            : index_(index), kind_(kindIndex) {
    }


    PathArgument::PathArgument(const char *key)
            : key_(key), kind_(kindKey) {
    }


    PathArgument::PathArgument(const std::string &key)
            : key_(key.c_str()), kind_(kindKey) {
    }

// class Path
// //////////////////////////////////////////////////////////////////

    Path::Path(const std::string &path,
               const PathArgument &a1,
               const PathArgument &a2,
               const PathArgument &a3,
               const PathArgument &a4,
               const PathArgument &a5) {
        InArgs in;
        in.push_back(&a1);
        in.push_back(&a2);
        in.push_back(&a3);
        in.push_back(&a4);
        in.push_back(&a5);
        makePath(path, in);
    }


    void
    Path::makePath(const std::string &path,
                   const InArgs &in) {
        const char *current = path.c_str();
        const char *end = current + path.length();
        InArgs::const_iterator itInArg = in.begin();
        while (current != end) {
            if (*current == '[') {
                ++current;
                if (*current == '%')
                    addPathInArg(path, in, itInArg, PathArgument::kindIndex);
                else {
                    Value::UInt index = 0;
                    for (; current != end && *current >= '0' && *current <= '9'; ++current)
                        index = index * 10 + Value::UInt(*current - '0');
                    args_.push_back(index);
                }
                if (current == end || *current++ != ']')
                    invalidPath(path, int(current - path.c_str()));
            } else if (*current == '%') {
                addPathInArg(path, in, itInArg, PathArgument::kindKey);
                ++current;
            } else if (*current == '.') {
                ++current;
            } else {
                const char *beginName = current;
                while (current != end && !strchr("[.", *current))
                    ++current;
                args_.push_back(std::string(beginName, current));
            }
        }
    }


    void
    Path::addPathInArg(const std::string &path,
                       const InArgs &in,
                       InArgs::const_iterator &itInArg,
                       PathArgument::Kind kind) {
        if (itInArg == in.end()) {
            // Error: missing argument %d
        } else if ((*itInArg)->kind_ != kind) {
            // Error: bad argument type
        } else {
            args_.push_back(**itInArg);
        }
    }


    void
    Path::invalidPath(const std::string &path,
                      int location) {
        // Error: invalid path.
    }


    const Value &
    Path::resolve(const Value &root) const {
        const Value *node = &root;
        for (Args::const_iterator it = args_.begin(); it != args_.end(); ++it) {
            const PathArgument &arg = *it;
            if (arg.kind_ == PathArgument::kindIndex) {
                if (!node->isArray() || node->isValidIndex(arg.index_)) {
                    // Error: unable to resolve path (array value expected at position...
                }
                node = &((*node)[arg.index_]);
            } else if (arg.kind_ == PathArgument::kindKey) {
                if (!node->isObject()) {
                    // Error: unable to resolve path (object value expected at position...)
                }
                node = &((*node)[arg.key_]);
                if (node == &Value::null) {
                    // Error: unable to resolve path (object has no member named '' at position...)
                }
            }
        }
        return *node;
    }


    Value
    Path::resolve(const Value &root,
                  const Value &defaultValue) const {
        const Value *node = &root;
        for (Args::const_iterator it = args_.begin(); it != args_.end(); ++it) {
            const PathArgument &arg = *it;
            if (arg.kind_ == PathArgument::kindIndex) {
                if (!node->isArray() || node->isValidIndex(arg.index_))
                    return defaultValue;
                node = &((*node)[arg.index_]);
            } else if (arg.kind_ == PathArgument::kindKey) {
                if (!node->isObject())
                    return defaultValue;
                node = &((*node)[arg.key_]);
                if (node == &Value::null)
                    return defaultValue;
            }
        }
        return *node;
    }


    Value &
    Path::make(Value &root) const {
        Value *node = &root;
        for (Args::const_iterator it = args_.begin(); it != args_.end(); ++it) {
            const PathArgument &arg = *it;
            if (arg.kind_ == PathArgument::kindIndex) {
                if (!node->isArray()) {
                    // Error: node is not an array at position ...
                }
                node = &((*node)[arg.index_]);
            } else if (arg.kind_ == PathArgument::kindKey) {
                if (!node->isObject()) {
                    // Error: node is not an object at position...
                }
                node = &((*node)[arg.key_]);
            }
        }
        return *node;
    }


} // namespace Json
